import json
from datetime import datetime

from pydantic import ValidationError
from fastapi.exceptions import RequestValidationError

from common import logger
from common.result import fail
from common.result import err_msg
from common.result import result_code
from fastapi import FastAPI
from starlette.requests import Request

from common.result.error import EtError

# 默认错误模板
undefined = "{name}参数:{meessage}"

# 常见的错误模板映射
_any_error = {
    'value_error.jsondecode': '传入的参数字段出现转换错误，请核对是否存在类型错误',
    'value_error.missing': '{name} 参数字段为必传参数',
    'value_error.any_str.max_length': '{name} 参数字段字符串长度最多{limit_value}位',
    'value_error.any_str.min_length': '{name} 参数字段字符串长度至少{limit_value}位以上',
    'value_error.number.not_gt': '{name} 参数字段数值必须大于{limit_value}',
    'value_error.number.not_le': '{name} 参数字段数值必须小于等于{limit_value}',
    "value_error.str.regex": "{name} 参数正则 {pattern} 匹配未通过",
    # =============================================
    'type_error.none.not_allowed': '{name} 参数字段值必须不能空值',
    "type_error.integer": "{name} 参数必须是一个int类型的参数",
    "type_error.float": "{name} 参数必须是一个float类型的参数",
}


def error_middleware(app: FastAPI):

    @app.exception_handler(Exception)
    async def _all_exception_handler(request: Request, exc: Exception):
        logger.error(f"[Api] 系统内部异常：{exc}")
        return fail(result=result_code.SysCont.Failed, msg=err_msg.FailErr, message="系统内部异常")

    @app.exception_handler(RequestValidationError)
    async def _validation_exception_handler(request: Request, exc: RequestValidationError):
        """捕获请求参数 验证错误"""
        return await _validatoion_error(request, exc)
        # return response_err(message="请求参数验证有误", status_code=ErrCode.param_err.code, data=json.loads(exc.json()))

    @app.exception_handler(ValidationError)
    async def _request_validatoion_error(request: Request, exc: ValidationError):
        """捕获请求参数 验证错误"""
        return await _validatoion_error(request, exc)
        # return response_err(message=str(exc.raw_errors), status_code=ErrCode.param_err.code, data=f"参数验证有误")

    @app.exception_handler(EtError)
    async def _et_validatoion_error(request: Request, exc: EtError):
        """捕获请求参数 EtError"""
        result_cont = exc.result_cont
        err_type = exc.err_type
        logger.error(f"[Api] 发生{err_type}异常：{exc.err_msg.text}")
        return fail(result=result_cont, msg=exc.err_msg)

    @app.exception_handler(AssertionError)
    async def __asser_exception_handler(request: Request, exc: AssertionError):
        if isinstance(exc.args[0], EtError):
            return await _et_validatoion_error(request, exc.args[0])
        logger.error(f"[Api] 断言错误，{exc}")
        return fail(result=result_code.SysCont.Failed, msg=err_msg.FailErr, message=str(exc))

    async def _validatoion_error(request: Request, exc: ValidationError):
        """捕获请求参数 验证错误"""
        logger.error(f"[Api] 参数验证异常：{json.loads(exc.json())}")

        try:
            body = await request.body()
            body = json.loads(body.decode("utf-8"))
        except:
            body = {}

        try:
            for err in exc.errors():
                if err["type"] == 'value_error.jsondecode':
                    err["msg"] = _any_error[err["type"]]
                    return fail(result=result_code.SysCont.ParameterAuthErr, msg=err_msg.FailErr, message=err["msg"])

                name, limit_value = ".".join([str(loc) for loc in err["loc"]]), None
                _value = err['ctx'] if "ctx" in err else {}
                limit_value = str(_value['limit_value']) if "limit_value" in _value else None
                pattern = _value['pattern'] if "pattern" in _value else None

                if err["type"] in _any_error:
                    if pattern:
                        err["msg"] = _any_error[err["type"]].format(name=name, pattern=pattern)
                    elif limit_value:
                        err["msg"] = _any_error[err["type"]].format(name=name, limit_value=limit_value)
                    else:
                        err["msg"] = _any_error[err["type"]].format(name=name)
                else:
                    err["msg"] = undefined.format(name=name, meessage=err["msg"])
                return fail(result=result_code.SysCont.ParameterAuthErr, msg=err_msg.FailErr, message=err["msg"])
        except Exception as e:
            logger.error(f"[Api] 参数验证错误信息解析异常：{e}")
            return fail(result=result_code.SysCont.ParameterAuthErr, msg=err_msg.FailErr, message=json.loads(exc.json()))

